package ms.unicorn.modellanguage;

import java.util.HashMap;
import java.util.Map;

import ms.unicorn.Element;
import ms.unicorn.diagram.edit.parts.EntityEditPart;
import ms.unicorn.diagram.edit.parts.RelationEditPart;
import ms.unicorn.util.FigureConstant;
import ms.unicorn.util.ErrorHandler;

import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.transaction.util.TransactionUtil;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gmf.runtime.common.core.command.CommandResult;
import org.eclipse.gmf.runtime.common.core.command.ICommand;
import org.eclipse.gmf.runtime.emf.core.util.EMFCoreUtil;
import org.eclipse.gmf.runtime.emf.type.core.IElementType;
import org.eclipse.gmf.runtime.emf.type.core.commands.ConfigureElementCommand;
import org.eclipse.gmf.runtime.emf.type.core.edithelper.AbstractEditHelperAdvice;
import org.eclipse.gmf.runtime.emf.type.core.requests.ConfigureRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.IEditCommandRequest;
import org.eclipse.gmf.runtime.notation.View;

public abstract class LanguageElementEditHelperAdvice extends AbstractEditHelperAdvice implements IElementEditHelperAdvice, FigureConstant {
	
	public static final String ENTITY_ID = "ms.unicorn.Entity";
	public static final String RElATION_ID = "ms.unicorn.Relation";
	
	protected Map<String, Class<? extends EditPart>> editPartMap = new HashMap<String, Class<? extends EditPart>>();
	
	public LanguageElementEditHelperAdvice() {
		super();
		editPartMap.put(ENTITY_ID, EntityEditPart.class);
		editPartMap.put(RElATION_ID, RelationEditPart.class);
	}

	@Override
	public ICommand getAfterEditCommand(IEditCommandRequest request) {
		if (request instanceof ConfigureRequest) {
			request.setParameter(IEditCommandRequest.REPLACE_DEFAULT_COMMAND, Boolean.TRUE);
			return new ConfigureElementCommand((ConfigureRequest) request) {
		
				@Override
				protected CommandResult doExecuteWithResult(
						IProgressMonitor monitor, IAdaptable info)
						throws ExecutionException {
					
					ConfigureRequest request = (ConfigureRequest) this.getRequest();
					Element domainElement = (Element) request.getElementToConfigure();
					IElementType type = request.getTypeToConfigure();
					if (type instanceof HintedSpecializationType)
						((HintedSpecializationType) type).getElement().getLanguage().configElement(domainElement, request);
					return CommandResult.newOKCommandResult();
				}
			};
		}
		return null;
	}

	@Override
	public EditPart createEditPart(EditPart context, Object model) {
		if (model instanceof View) {
			View view = (View)model;
			String viewType = view.getType();
			Class<? extends EditPart> editPartClass = editPartMap.get(viewType);
			if (editPartClass != null) {
				try {
					return editPartClass.getConstructor(View.class).newInstance(view);
				} catch (Exception e) {
					ErrorHandler.handleException(e);
				} 
			}
		}
		return null;
	}

	@Override
	public EditPolicy createPrimaryDragEditPolicy(Element element, EditPart editPart) {
		return null;
	}

	protected EObject getSemanticElement(IAdaptable semanticAdapter) {
		if (semanticAdapter == null) {
			return null;
		}
		EObject eObject = (EObject) semanticAdapter.getAdapter(EObject.class);
		if (eObject != null) {
			return EMFCoreUtil.resolve(
					TransactionUtil.getEditingDomain(eObject), eObject);
		}
		return null;
	}
}